home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Mail
/
pine3.92
/
pico
/
os_vms.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-14
|
33KB
|
1,514 lines
#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: os_vms.c,v 1.17 1996/03/15 07:41:11 hubert Exp $";
#endif
/*
* Program: Operating system dependent routines - VMS 5.n
*
*
* Yehavi Bourvine
* Hebrew University of Jeruselem
* +972-2-585684
* YEHAVI@vms.huji.ac.il
*
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
*
*
* Pine and Pico are registered trademarks of the University of Washington.
* No commercial use of these trademarks may be made without prior written
* permission of the University of Washington.
*
* Pine, Pico, and Pilot software and its included text are Copyright
* 1989-1996 by the University of Washington.
*
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this distribution.
*/
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include "osdep.h"
#include "pico.h"
#include "estruct.h"
#include "edef.h"
#include "efunc.h"
#ifdef __ALPHA
#include <fcntl.h>
#endif
#include <file.h>
#include <types.h>
#include <time.h>
#include <iodef.h>
#include <ttdef.h>
#include <tt2def.h>
#include <lib$routines.h>
#include <descrip.h>
/* Output channel and buffers */
static short TerminalChan;
#define MAXBUF 1024 /* Save up to 1024 characters before sending them */
unsigned char OutputBuffer[MAXBUF + 1];
int OutputBufferCounter;
int timeout = 0;
/* For setting and resting the PASTHRU flag: */
struct {
unsigned char class, type;
unsigned short width;
unsigned long BasicChar,
ExtendChar;
} TerminalChar;
#define SIGTYPE void
struct DESC { /* String descriptor */
short length, type;
char *address;
} ;
int kbseq();
SIGTYPE do_hup_signal();
SIGTYPE rtfrmshell();
#ifdef TIOCGWINSZ
SIGTYPE winch_handler();
#endif
/*
* for alt_editor arg[] building
*/
#define MAXARGS 10
/*
* ttopen - this function is called once to set up the terminal device
* streams. if called as pine composer, don't mess with
* tty modes, but set signal handlers.
*/
ttopen()
{
long status;
struct DESC TerminalDesc;
char TerminalName[] = "SYS$OUTPUT:";
int row, col;
TerminalDesc.address = TerminalName; TerminalDesc.type = 0;
TerminalDesc.length = strlen(TerminalName);
status = sys$assign(&TerminalDesc, &TerminalChan, (int)(0), (int)(0));
if((status & 0x1) == 0) {
printf("Can't assign channel to terminal\n");
exit(status);
}
signal(SIGHUP, do_hup_signal); /* deal with SIGHUP */
signal(SIGTERM, do_hup_signal); /* deal with SIGTERM */
#ifdef SIGTSTP
signal(SIGTSTP, SIG_DFL);
#endif
/* Some default values since we do not have TERMCAP: */
eolexist = FALSE;
revexist = TRUE;
delchar = FALSE;
inschar = FALSE;
scrollexist = TRUE;
init_kpnames();
OutputBufferCounter = 0; /* Output buffer is empty */
/* Set the PASTHRU bit */
status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SENSEMODE),
NULL, (int)(0), (int)(0),
&TerminalChar, sizeof(TerminalChar),
(int)(0), (int)(0), (int)(0), (int)(0));
if((status & 0x1) == 0) {
printf("Can't read for set terminal to /PASTHRU\n");
exit(status);
}
TerminalChar.ExtendChar |= TT2$M_PASTHRU;
status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SETMODE),
NULL, (int)(0), (int)(0),
&TerminalChar, sizeof(TerminalChar),
(int)(0), (int)(0), (int)(0), (int)(0));
if((status & 0x1) == 0) {
printf("Can't set terminal to /PASTHRU\n");
exit(status);
}
ttgetwinsz(&row, &col);
term.t_nrow = row;
term.t_ncol = col;
return(1);
}
/*
* ttresize - recompute the screen dimensions if necessary, and then
* adjust pico's internal buffers accordingly.
*/
int
ttresize ()
{
int row, col;
ttgetwinsz(&row, &col);
resize_pico(row, col);
}
/*
* ttclose - this function gets called just before we go back home to
* the command interpreter. If called as pine composer, don't
* worry about modes, but set signals to default, pine will
* rewire things as needed.
*/
ttclose()
{
int status;
ttflush();
/* Clear the PASTHRU flag */
TerminalChar.ExtendChar &= ~TT2$M_PASTHRU;
status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SETMODE),
NULL, (int)(0), (int)(0),
&TerminalChar, sizeof(TerminalChar),
(int)(0), (int)(0), (int)(0), (int)(0));
if((status & 0x1) == 0) {
printf("Can't set terminal to /NOPASTHRU\n");
exit(status);
}
sys$dassgn(TerminalChan);
return(1);
}
/*
* ttspeed - return TRUE if tty line speed < 9600 else return FALSE
*/
ttisslow()
{
return(TRUE);
}
/*
* ttgetwinsz - set global rows and columns values and return
*/
ttgetwinsz(row, col)
int *row, *col;
{
#define TT_STRING_SIZE 20
char string[TT_STRING_SIZE] ; /* string for holding tt:'s dev name */
int rows, cols ; /* row / column vars */
unsigned long status ; /* status return var */
unsigned long terminal_item = 797 ; /* JPI$_TERMINAL */
unsigned long tt_page_item = 170 ; /* DVI$_TT_PAGE */
unsigned long devbufsz_item = 8 ; /* DVI$_DEVBUFSIZ */
struct dsc$descriptor_vs tt_sdesc =
{TT_STRING_SIZE,/* max string size */
DSC$K_DTYPE_VT, /* descriptor type */
DSC$K_CLASS_VS, /* descriptor class = var str */
string} ; /* pointer to var string */
/* Set the defaults */
*row = NROW - 1;
*col = NCOL;
/* Get our terminal's device name */
status = lib$getjpi(&terminal_item,NULL,NULL,NULL,&tt_sdesc,NULL) ;
if ((status&1) == 1)
{
/* Get our terminal's page size */
status = lib$getdvi(&tt_page_item,NULL,&tt_sdesc,&rows,NULL,NULL) ;
/* Get our terminal's page width */
if((status & 0x1) == 1) {
status = lib$getdvi(&devbufsz_item,NULL,&tt_sdesc,&cols,NULL,NULL) ;
if((status & 0x1) == 1) {
/* Set the globals for rows and columns */
*row = rows-1 ;
*col = cols ;
}
}
}
else
printf("Can't find process's terminal -- using defaults.\n") ;
}
/*
| Physically write a string to the terminal.
*/
write_terminal(string, size)
char *string;
int size;
{
long status;
short iosb[4];
status = sys$qiow((int)(0), TerminalChan, (short)(IO$_WRITEVBLK),
iosb, (int)(0), (int)(0),
string, size, (int)(0), (int)(0), (int)(0), (int)(0));
if(((status & 0x1) == 0) || ((iosb[0] & 0x1) == 0)) {
printf("Can't write to terminal; status=%d, iosb=%d\n",
status, iosb[0]);
exit(status);
}
return 0; /* Success */
}
/*
* __ttputc - Write a character to the display. Actually save it in our buffer
* and write it only if the buffer is becoming full.
* This function is called by TTPUTC().
*/
__ttputc(c)
{
OutputBuffer[OutputBufferCounter++] = c;
if(OutputBufferCounter >= MAXBUF)
ttflush();
return c;
}
/*
* ttputc - Write a character to the display. Actually save it in our buffer
* and write it only if the buffer is becoming full.
*/
#undef ttputc
ttputc(c)
{
return(__ttputc(c));
}
/*
* ttflush - Flush our buffer to the terminal.
*/
ttflush()
{
if(OutputBufferCounter > 0) {
write_terminal(OutputBuffer, OutputBufferCounter);
OutputBufferCounter = 0;
}
}
/*
* ttgetc - Read a character from the terminal, performing no editing
* and doing no echo at all.
*/
ttgetc()
{
unsigned char c;
int i;
long status;
unsigned long Terminator[4] = { -1, -1, -1, -1};
struct DESC TerminatorDesc = { sizeof(Terminator), 0, Terminator };
short iosb[4];
status = sys$qiow((int)(0), TerminalChan,
(short)(IO$_READLBLK | IO$M_NOFORMAT | IO$M_NOFILTR | IO$M_NOECHO | IO$M_TRMNOECHO),
iosb, (int)(0), (int)(0),
&c, 1, (int)(0), &TerminatorDesc, (int)(0), (int)(0));
if(((status & 0x1) == 0) || ((iosb[0] & 0x1) == 0)) {
printf("Can't read from terminal; status=%d, iosb=%d\n",
status, iosb[0]);
exit(status);
}
c &= 0xff;
if(c == 155) c = 27; /* Convert 8th bit escape to 7bit one */
return((int)(c));
}
/*
* GetKey - Read in a key.
* Do the standard keyboard preprocessing. Convert the keys to the internal
* character set. Resolves escape sequences and returns no-op if global
* timeout value exceeded.
*/
GetKey()
{
int c, status, cc;
/*~~~ HUJI/VMS - No timeout is supported on VMS to make it simple... */
switch(status = kbseq(pico_kbesc, term.t_getchar, &c)){
case 0: /* regular character */
break;
case K_DOUBLE_ESC:
c = (*term.t_getchar)();
if(islower(c)) /* canonicalize c */
c = toupper(c);
return((isalpha(c) || c == '@' || (c >= '[' && c <= '_'))
? (CTRL | c) : c);
case K_PAD_UP :
case K_PAD_DOWN :
case K_PAD_RIGHT :
case K_PAD_LEFT :
case K_PAD_PREVPAGE :
case K_PAD_NEXTPAGE :
case K_PAD_HOME :
case K_PAD_END :
case K_PAD_DELETE :
case F1 :
case F2 :
case F3 :
case F4 :
case F5 :
case F6 :
case F7 :
case F8 :
case F9 :
case F10 :
case F11 :
case F12 :
return(status);
case K_SWALLOW_TIL_Z:
status = NODATA;
case K_SWALLOW_UP:
case K_SWALLOW_DOWN:
case K_SWALLOW_LEFT:
case K_SWALLOW_RIGHT:
for(cc = 0; cc != 'z' && cc != '~';)
cc = (*term.t_getchar)() & 0x7f;
return(status);
break;
case K_KERMIT:
for(cc = 0; cc != '\033' || ((*term.t_getchar)() & 0x7f) != '\\';)
cc = (*term.t_getchar)() & 0x7f;
c = NODATA;
break;
case BADESC:
(*term.t_beep)();
return(status);
default: /* punt the whole thing */
(*term.t_beep)();
break;
}
if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
c = CTRL | (c+'@');
return (c);
}
/*
* kbseq - looks at an escape sequence coming from the keyboard and
* compares it to a trie of known keyboard escape sequences, and
* performs the function bound to the escape sequence.
*
* returns: BADESC, the escaped function, or 0 if a regular char.
*/
kbseq(trie, getcfunc, c)
KBESC_T *trie;
int (*getcfunc)();
int *c;
{
register char b;
register int first = 1;
register KBESC_T *current = trie;
if(trie == NULL) /* bag it */
return(BADESC);
while(1){
b = *c = (*getcfunc)();
while(current->value != b){
if(current->left == NULL){ /* NO MATCH */
if(first)
return(0); /* regular char */
else
return(BADESC);
}
current = current->left;
}
if(current->down == NULL) /* match!!!*/
return(current->func);
else
current = current->down;
first = 0;
}
}
/*
* alt_editor - Use normal SYSTEM() and not fork.
*/
alt_editor(f, n)
{
char eb[NLINE]; /* buf holding edit command */
char *fn; /* tmp holder for file name */
char *cp;
long l;
int i, pid, done = 0;
if(Pmaster == NULL)
return;
if(gmode&MDSCUR){
emlwrite("Alternate editor not available in restricted mode", NULL);
return;
}
if(Pmaster->alt_ed == NULL){
if(!(gmode&MDADVN)){
emlwrite("\007Unknown Command",NULL);
return;
}
if(getenv("EDITOR"))
strcpy(eb, (char *)getenv("EDITOR"));
else
*eb = '\0';
while(!done){
pid = mlreplyd("Which alternate editor ? ", eb, NLINE, QDEFLT);
switch(pid){
case ABORT:
return(-1);
case HELPCH:
emlwrite("no alternate editor help yet", NULL);
/* take sleep and break out after there's help */
sleep(3);
break;
case (CTRL|'L'):
sgarbf = TRUE;
update();
break;
case TRUE:
case FALSE: /* does editor exist ? */
if(*eb == '\0'){ /* leave silently? */
mlerase();
return(-1);
}
done++;
break;
default:
break;
}
}
}
else
strcpy(eb, Pmaster->alt_ed);
if((fn=writetmp(0, 1)) == NULL){ /* get temp file */
emlwrite("Problem writing temp file for alt editor", NULL);
return(-1);
}
strcat(eb, " ");
/* fn is /SYS$SCRATCH/filename; Modify it to suit DCL style... */
if((cp = strrchr(fn, '/')) != NULL) {
strcat(eb, "SYS$SCRATCH:"); strcat(eb, &cp[1]);
} else strcat(eb, fn);
cp = eb;
if(Pmaster)
(*Pmaster->raw_io)(0); /* turn OFF raw mode */
system(eb);
if(Pmaster)
(*Pmaster->raw_io)(1); /* turn ON raw mode */
/*
* replace edited text with new text
*/
curbp->b_flag &= ~BFCHG; /* make sure old text gets blasted */
readin(fn, 0); /* read new text overwriting old */
unlink(fn); /* blast temp file */
curbp->b_flag |= BFCHG; /* mark dirty for packbuf() */
ttopen(); /* reset the signals */
refresh(0, 1); /* redraw */
}
/*
* bktoshell - suspend and wait to be woken up
*/
bktoshell() /* suspend MicroEMACS and wait to wake up */
{
emlwrite("\007Unknown command (in BktoShell): ^Z", NULL);
return;
}
/*
* rtfrmshell - back from shell, fix modes and return
*/
SIGTYPE
rtfrmshell()
{
}
/*
* do_hup_signal - jump back in the stack to where we can handle this
*/
SIGTYPE
do_hup_signal()
{
if(Pmaster){
extern jmp_buf finstate;
signal(SIGHUP, SIG_IGN); /* don't bother us. */
signal(SIGTERM, SIG_IGN);
longjmp(finstate, COMP_GOTHUP);
}
else{
/*
* if we've been interrupted and the buffer is changed,
* save it...
*/
if(anycb() == TRUE){ /* time to save */
if(curbp->b_fname[0] == '\0'){ /* name it */
strcpy(curbp->b_fname, "pico.save");
}
else{
strcat(curbp->b_fname, ".save");
}
writeout(curbp->b_fname);
}
vttidy();
exit(1);
}
}
unlink(fn)
char *fn;
{
delete(fn);
}
/*
* big bitmap of ASCII characters allowed in a file name
* (needs reworking for other char sets)
*/
unsigned char okinfname[32] = {
0, 0, /* ^@ - ^G, ^H - ^O */
0, 0, /* ^P - ^W, ^X - ^_ */
0xff, 0xff, /* SP - ' , ( - / */
0xff, 0xff, /* 0 - 7 , 8 - ? */
0xff, 0xff, /* @ - G , H - O */
0xff, 0xff, /* P - W , X - _ */
0xff, 0xff, /* ` - g , h - o */
0xff, 0xff, /* p - w , x - DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0 /* > DEL */
};
/*
* fallowc - returns TRUE if c is allowable in filenames, FALSE otw
*/
fallowc(c)
char c;
{
return(okinfname[c>>3] & 0x80>>(c&7));
}
/*
* fexist - returns TRUE if the file exists with mode passed in m,
* FALSE otherwise. By side effect returns length of file in l
*/
fexist(file, m, l)
char *file;
char *m; /* files mode: r, w or rw */
long *l;
{
struct stat sbuf;
if(l)
*l = 0L;
if(stat(file, &sbuf) < 0){
switch(errno){
case ENOENT : /* File not found */
return(FIOFNF);
#ifdef ENAMETOOLONG
case ENAMETOOLONG : /* Name is too long */
return(FIOLNG);
#endif
default: /* Some other error */
return(FIOERR);
}
}
if(l)
*l = sbuf.st_size;
if((sbuf.st_mode&S_IFMT) == S_IFDIR)
return(FIODIR);
else if(*m == 't') /* no links, just say yes */
return(FIOSUC);
if(*m == 'r'){
if(*(m+1) == 'w') /* read access? */
return((S_IREAD&sbuf.st_mode)
? ((S_IWRITE&sbuf.st_mode))
? FIOSUC
: FIONWT
: FIONRD);
else
return((S_IREAD&sbuf.st_mode) ? FIOSUC : FIONRD);
}
else if(*m == 'w') /* write access? */
return((S_IWRITE&sbuf.st_mode) ? FIOSUC : FIONWT);
else if(*m == 'x') /* execute access? */
return((S_IEXEC&sbuf.st_mode) ? FIOSUC : FIONEX);
return(FIOERR); /* what? */
}
/*
* isdir - returns true if fn is a readable directory, false otherwise
* silent on errors (we'll let someone else notice the problem;)).
*/
isdir(fn, l)
char *fn;
long *l;
{
struct stat sbuf;
if(l)
*l = 0;
if(stat(fn, &sbuf) < 0)
return(0);
if(l)
*l = sbuf.st_size;
return((sbuf.st_mode&S_IFMT) == S_IFDIR);
}
/*
* gethomedir - returns the users home directory
* Note: home is malloc'd for life of pico
*/
char *
gethomedir(l)
int *l;
{
static char *home = NULL;
static short hlen = 0;
char s[1024];
if(home == NULL){
strcpy(s, getenv("HOME"));
hlen = strlen(s);
if((home=(char *)malloc((strlen(s) + 1) * sizeof(char))) == NULL){
emlwrite("Problem allocating space for home dir", NULL);
return(0);
}
strcpy(home, s);
}
if(l)
*l = hlen;
return(home);
}
/*
* homeless - returns true if given file does not reside in the current
* user's home directory tree.
*/
homeless(f)
char *f;
{
char *home;
int len;
home = gethomedir(&len);
return(strncmp(home, f, len));
}
/*
* errstr - return system error string corresponding to given errno
* Note: strerror() is not provided on all systems, so it's
* done here once and for all.
*/
char *
errstr(err)
int err;
{
extern char *sys_errlist[];
extern int sys_nerr;
return((err >= 0 && err < sys_nerr) ? sys_errlist[err] : NULL);
}
/*
* getfnames - return all file names in the given directory in a single
* malloc'd string. n contains the number of names
*/
char *
getfnames(dn, pat, n, e)
char *dn, *pat, *e;
int *n;
{
char *ddn; /* Don't ruin the original */
int context = 0; /* Used in LIB$FIND_FILE */
struct DESC file_mask, file_name;
int status;
char *p, *OutputPointer;
char *RetFiles = malloc(8192); /* Hopefully it will be enough... */
char FileName[256]; /* Temporary place */
*n = 0; /* Init - no files yet */
if(RetFiles == NULL) return;
*(OutputPointer = RetFiles) = '\0';
/* For all directory names append *.* for the finction to succeed */
strcpy(ddn, dn); /* Don't ruin it */
strcat(ddn, "*.*");
file_mask.length = strlen(ddn); file_mask.address = ddn;
file_mask.type = 0;
for(;;) {
file_name.address = FileName; file_name.length = sizeof(FileName) - 1;
file_name.type = 0;
status = LIB$FIND_FILE(&file_mask, &file_name, &context);
if((status & 0x1) == 0) {
if(context != 0)
LIB$FIND_FILE_END(&context);
context = 0; /* Init for next search */
return RetFiles;
}
/* File found - Remove the leading directory name and the trailing spaces */
if((p = strchr(FileName, ' ')) != NULL) *p = '\0';
if((p = strrchr(FileName, ']')) != NULL) p++;
else p = FileName;
if(!pat || !*pat || strucmp(p, pat, strlen(pat))){
while((*OutputPointer++ = *p++) != '\0');
*n += 1;
}
}
}
/*
* fioperr - given the error number and file name, display error
*/
void
fioperr(e, f)
int e;
char *f;
{
switch(e){
case FIOFNF: /* File not found */
emlwrite("\007File \"%s\" not found", f);
break;
case FIOEOF: /* end of file */
emlwrite("\007End of file \"%s\" reached", f);
break;
case FIOLNG: /* name too long */
emlwrite("\007File name \"%s\" too long", f);
break;
case FIODIR: /* file is a directory */
emlwrite("\007File \"%s\" is a directory", f);
break;
case FIONWT:
emlwrite("\007Write permission denied: %s", f);
break;
case FIONRD:
emlwrite("\007Read permission denied: %s", f);
break;
case FIONEX:
emlwrite("\007Execute permission denied: %s", f);
break;
default:
emlwrite("\007File I/O error: %s", f);
}
}
/*
* pfnexpand - pico's function to expand the given file name if there is
* a leading '~'
*/
char *pfnexpand(fn, len)
char *fn;
int len;
{
char *pw;
register char *x, *y, *z;
char name[256];
if(*fn == '~') {
for(x = fn+1, y = name; *x != '/' && *x != '\0'; *y++ = *x++);
*y = '\0';
if(x == fn + 1)
pw = getenv("HOME");
else
pw = NULL;
if(pw == NULL)
return(NULL);
/* make room for expanded path */
for(z=x+strlen(x),y=fn+strlen(x)+strlen(pw);
z >= x;
*y-- = *z--);
/* and insert the expanded address */
for(x=fn,y=pw; *y != '\0'; *x++ = *y++);
}
return(fn);
}
/*
* fixpath - do nothing...
*/
fixpath(name, len)
char *name;
int len;
{
}
/*
* compresspath - given a base path and an additional directory, collapse
* ".." and "." elements and return absolute path (appending
* base if necessary).
*
* returns 1 if OK,
* 0 if there's a problem
* new path, by side effect, if things went OK
*/
compresspath(base, path, len)
char *base, *path;
int len;
{
register int i;
int depth = 0;
char *p;
char *stack[32];
char s[1024];
#define PUSHD(X) (stack[depth++] = X)
#define POPD() ((depth > 0) ? stack[--depth] : "")
if(*path == '~'){
fixpath(path, len);
strcpy(s, path);
}
else if(*path != C_FILESEP)
sprintf(s, "%s%c%s", base, C_FILESEP, path);
else
strcpy(s, path);
p = s;
for(i=0; s[i] != '\0'; i++){ /* pass thru path name */
if(s[i] == '/'){
if(p != s)
PUSHD(p); /* push dir entry */
p = &s[i+1]; /* advance p */
s[i] = '\0'; /* cap old p off */
continue;
}
if(s[i] == '.'){ /* special cases! */
if(s[i+1] == '.' /* parent */
&& (s[i+2] == '/' || s[i+2] == '\0')){
if(!strcmp(POPD(),"")) /* bad news! */
return(0);
i += 2;
p = (s[i] == '\0') ? "" : &s[i+1];
}
else if(s[i+1] == '/' || s[i+1] == '\0'){ /* no op */
i++;
p = (s[i] == '\0') ? "" : &s[i+1];
}
}
}
if(*p != '\0')
PUSHD(p); /* get last element */
path[0] = '\0';
for(i = 0; i < depth; i++){
strcat(path, S_FILESEP);
strcat(path, stack[i]);
}
return(1); /* everything's ok */
}
/*
* tmpname - return a temporary file name in the given buffer
*/
void
tmpname(name)
char *name;
{
sprintf(name, "/SYS$SCRATCH/pico.%d", getpid()); /* tmp file name */
}
/*
* Take a file name, and from it
* fabricate a buffer name. This routine knows
* about the syntax of file names on the target system.
* I suppose that this information could be put in
* a better place than a line of code.
*/
void
makename(bname, fname)
char bname[];
char fname[];
{
register char *cp1;
register char *cp2;
cp1 = &fname[0];
while (*cp1 != 0)
++cp1;
while (cp1!=&fname[0] && cp1[-1]!='/')
--cp1;
cp2 = &bname[0];
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
*cp2++ = *cp1++;
*cp2 = 0;
}
/*
* copy - copy contents of file 'a' into a file named 'b'. Return error
* if either isn't accessible or is a directory
*/
copy(a, b)
char *a, *b;
{
int in, out, n, rv = 0;
char *cb;
struct stat tsb, fsb;
extern int errno;
if(stat(a, &fsb) < 0){ /* get source file info */
emlwrite("Can't Copy: %s", errstr(errno));
return(-1);
}
if(!(fsb.st_mode&S_IREAD)){ /* can we read it? */
emlwrite("\007Read permission denied: %s", a);
return(-1);
}
if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
emlwrite("\007Can't copy: %s is a directory", a);
return(-1);
}
if(stat(b, &tsb) < 0){ /* get dest file's mode */
switch(errno){
case ENOENT:
break; /* these are OK */
default:
emlwrite("\007Can't Copy: %s", errstr(errno));
return(-1);
}
}
else{
if(!(tsb.st_mode&S_IWRITE)){ /* can we write it? */
emlwrite("\007Write permission denied: %s", b);
return(-1);
}
if((tsb.st_mode&S_IFMT) == S_IFDIR){ /* is it directory? */
emlwrite("\007Can't copy: %s is a directory", b);
return(-1);
}
if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
emlwrite("\007Identical files. File not copied", NULL);
return(-1);
}
}
if((in = open(a, O_RDONLY)) < 0){
emlwrite("Copy Failed: %s", errstr(errno));
return(-1);
}
if((out=creat(b, fsb.st_mode&0xfff)) < 0){
emlwrite("Can't Copy: %s", errstr(errno));
close(in);
return(-1);
}
if((cb = (char *)malloc(NLINE*sizeof(char))) == NULL){
emlwrite("Can't allocate space for copy buffer!", NULL);
close(in);
close(out);
return(-1);
}
while(1){ /* do the copy */
if((n = read(in, cb, NLINE)) < 0){
emlwrite("Can't Read Copy: %s", errstr(errno));
rv = -1;
break; /* get out now */
}
if(n == 0) /* done! */
break;
if(write(out, cb, n) != n){
emlwrite("Can't Write Copy: %s", errstr(errno));
rv = -1;
break;
}
}
free(cb);
close(in);
close(out);
return(rv);
}
/*
* Open a file for writing. Return TRUE if all is well, and FALSE on error
* (cannot create).
*/
ffwopen(fn)
char *fn;
{
extern FILE *ffp;
if ((ffp=fopen(fn, "w")) == NULL) {
emlwrite("Cannot open file for writing", NULL);
return (FIOERR);
}
return (FIOSUC);
}
/*
* Close a file. Should look at the status in all systems.
*/
ffclose()
{
extern FILE *ffp;
if (fclose(ffp) != FALSE) {
emlwrite("Error closing file", NULL);
return(FIOERR);
}
return(FIOSUC);
}
/*
* P_open - run the given command in a sub-shell returning a file pointer
* from which to read the output
*
* note:
* For OS's other than unix, you will have to rewrite this function.
* Hopefully it'll be easy to exec the command into a temporary file,
* and return a file pointer to that opened file or something.
*/
FILE *P_open(s)
char *s;
{
printf("Popen not supported on VMS yet.\n");
return NULL;
}
/*
* P_close - close the given descriptor
*
*/
P_close(fp)
FILE *fp;
{
return;
}
/*
* worthit - generic sort of test to roughly gage usefulness of using
* optimized scrolling.
*
* note:
* returns the line on the screen, l, that the dot is currently on
*/
worthit(l)
int *l;
{
int i; /* l is current line */
unsigned below; /* below is avg # of ch/line under . */
*l = doton(&i, &below);
below = (i > 0) ? below/(unsigned)i : 0;
return(below > 3);
}
/*
* pico_new_mail - just checks mtime and atime of mail file and notifies user
* if it's possible that they have new mail.
*/
pico_new_mail()
{
int ret = 0;
static time_t lastchk = 0;
struct stat sbuf;
char inbox[256], *p;
sprintf(inbox,"SYS$LOGIN:MAIL.MAI");
if(stat(inbox, &sbuf) == 0){
ret = sbuf.st_atime <= sbuf.st_mtime &&
(lastchk < sbuf.st_mtime && lastchk < sbuf.st_atime);
lastchk = sbuf.st_mtime;
return(ret);
}
else
return(ret);
}
/*
* time_to_check - checks the current time against the last time called
* and returns true if the elapsed time is > timeout
*/
time_to_check()
{
static time_t lasttime = 0L;
if(!timeout)
return(FALSE);
if(time((long *) 0) - lasttime > (time_t)timeout){
lasttime = time((long *) 0);
return(TRUE);
}
else
return(FALSE);
}
/*
* sstrcasecmp - compare two pointers to strings case independently
*/
sstrcasecmp(s1, s2)
QcompType *s1, *s2;
{
register char *a, *b;
a = *(char **)s1;
b = *(char **)s2;
while(toupper(*a) == toupper(*b++))
if(*a++ == '\0')
return(0);
return(toupper(*a) - toupper(*--b));
}
/*
* chkptinit -- initialize anything we need to support composer
* checkpointing
*/
chkptinit(file, n)
char *file;
int n;
{
unsigned pid;
char *chp;
long gmode_save;
gmode_save = gmode;
if(gmode&MDCURDIR)
gmode &= ~MDCURDIR; /* so fixpath will use home dir */
strcpy(file, "#picoXXXXX#");
fixpath(file, NLINE);
pid = (unsigned)getpid();
for(chp = file + strlen(file) - 2; *chp == 'X'; chp--){
*chp = (pid % 10) + '0';
pid /= 10;
}
gmode = gmode_save;
unlink(file);
}
#ifdef TIOCGWINSZ
/*
* winch_handler - handle window change signal
*/
SIGTYPE winch_handler()
{
struct winsize win;
extern int resize_pico();
signal(SIGWINCH, winch_handler);
if (ioctl(0, TIOCGWINSZ, &win) == 0) {
if (win.ws_col && win.ws_row)
resize_pico(win.ws_row - 1, win.ws_col);
}
}
#endif /* TIOCGWINSZ */
/* Copied from TCAP */
hide_cur()
{
write_terminal("\033[?25l", 6);
}
show_cur()
{
write_terminal("\033[?25h", 6);
}
o_insert()
{
return 0;
}
o_delete()
{
return 0;
}
/*
* add default keypad sequences to the trie...
*/
init_kpnames()
{
/*
* UW-NDC/UCS vt10[02] application mode.
*/
kpinsert(&pico_kbesc, "\033OP", F1);
kpinsert(&pico_kbesc, "\033OQ", F2);
kpinsert(&pico_kbesc, "\033OR", F3);
kpinsert(&pico_kbesc, "\033OS", F4);
kpinsert(&pico_kbesc, "\033Op", F5);
kpinsert(&pico_kbesc, "\033Oq", F6);
kpinsert(&pico_kbesc, "\033Or", F7);
kpinsert(&pico_kbesc, "\033Os", F8);
kpinsert(&pico_kbesc, "\033Ot", F9);
kpinsert(&pico_kbesc, "\033Ou", F10);
kpinsert(&pico_kbesc, "\033Ov", F11);
kpinsert(&pico_kbesc, "\033Ow", F12);
/*
* DC vt100, ANSI and cursor key mode.
*/
kpinsert(&pico_kbesc, "\033OA", K_PAD_UP);
kpinsert(&pico_kbesc, "\033OB", K_PAD_DOWN);
kpinsert(&pico_kbesc, "\033OC", K_PAD_RIGHT);
kpinsert(&pico_kbesc, "\033OD", K_PAD_LEFT);
/*
* special keypad functions
*/
kpinsert(&pico_kbesc, "\033[4J", K_PAD_PREVPAGE);
kpinsert(&pico_kbesc, "\033[3J", K_PAD_NEXTPAGE);
kpinsert(&pico_kbesc, "\033[2J", K_PAD_HOME);
kpinsert(&pico_kbesc, "\033[N", K_PAD_END);
/*
* ANSI mode.
*/
kpinsert(&pico_kbesc, "\033[=a", F1);
kpinsert(&pico_kbesc, "\033[=b", F2);
kpinsert(&pico_kbesc, "\033[=c", F3);
kpinsert(&pico_kbesc, "\033[=d", F4);
kpinsert(&pico_kbesc, "\033[=e", F5);
kpinsert(&pico_kbesc, "\033[=f", F6);
kpinsert(&pico_kbesc, "\033[=g", F7);
kpinsert(&pico_kbesc, "\033[=h", F8);
kpinsert(&pico_kbesc, "\033[=i", F9);
kpinsert(&pico_kbesc, "\033[=j", F10);
kpinsert(&pico_kbesc, "\033[=k", F11);
kpinsert(&pico_kbesc, "\033[=l", F12);
/*
* DEC vt100, ANSI, cursor key mode reset.
*/
kpinsert(&pico_kbesc, "\033[A", K_PAD_UP);
kpinsert(&pico_kbesc, "\033[B", K_PAD_DOWN);
kpinsert(&pico_kbesc, "\033[C", K_PAD_RIGHT);
kpinsert(&pico_kbesc, "\033[D", K_PAD_LEFT);
/*
* DEC vt52 mode.
*/
kpinsert(&pico_kbesc, "\033A", K_PAD_UP);
kpinsert(&pico_kbesc, "\033B", K_PAD_DOWN);
kpinsert(&pico_kbesc, "\033C", K_PAD_RIGHT);
kpinsert(&pico_kbesc, "\033D", K_PAD_LEFT);
/*
* DEC vt52 application keys, and some Zenith 19.
*/
kpinsert(&pico_kbesc, "\033?r", K_PAD_DOWN);
kpinsert(&pico_kbesc, "\033?t", K_PAD_LEFT);
kpinsert(&pico_kbesc, "\033?v", K_PAD_RIGHT);
kpinsert(&pico_kbesc, "\033?x", K_PAD_UP);
/*
* Sun Console sequences.
*/
kpinsert(&pico_kbesc, "\033[1", K_SWALLOW_TIL_Z);
kpinsert(&pico_kbesc, "\033[215", K_SWALLOW_UP);
kpinsert(&pico_kbesc, "\033[217", K_SWALLOW_LEFT);
kpinsert(&pico_kbesc, "\033[219", K_SWALLOW_RIGHT);
kpinsert(&pico_kbesc, "\033[221", K_SWALLOW_DOWN);
/*
* Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
*/
kpinsert(&pico_kbesc, "\033_", K_KERMIT);
/*
* Fake a control character.
*/
kpinsert(&pico_kbesc, "\033\033", K_DOUBLE_ESC);
}
#define newnode() (KBESC_T *)malloc(sizeof(KBESC_T))
/*
* kpinsert - insert a keystroke escape sequence into the global search
* structure.
*/
void
kpinsert(trie, kstr, kval)
KBESC_T **trie;
char *kstr;
int kval;
{
register char *buf;
register KBESC_T *temp;
register KBESC_T *trail;
if(kstr == NULL)
return;
/*
* Don't allow escape sequences that don't start with ESC.
*/
if(*kstr != '\033')
return;
temp = trail = *trie;
buf = kstr;
for(;;) {
if(temp == NULL){
temp = newnode();
temp->value = *buf;
temp->func = 0;
temp->left = NULL;
temp->down = NULL;
if(*trie == NULL)
*trie = temp;
else
trail->down = temp;
}
else{ /* first entry */
while((temp != NULL) && (temp->value != *buf)){
trail = temp;
temp = temp->left;
}
if(temp == NULL){ /* add new val */
temp = newnode();
temp->value = *buf;
temp->func = 0;
temp->left = NULL;
temp->down = NULL;
trail->left = temp;
}
}
if(*(++buf) == '\0')
break;
else{
/*
* Ignore attempt to overwrite shorter existing escape sequence.
* That means that sequences with higher priority should be
* set up first.
*/
if(temp->func != 0)
return;
trail = temp;
temp = temp->down;
}
}
/*
* Ignore attempt to overwrite longer sequences we are a prefix
* of (down != NULL) and exact same sequence (func != 0).
*/
if(temp != NULL && temp->down == NULL && temp->func == 0)
temp->func = kval;
}